// Copyright 2009 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.android.stardroid.renderer;

import android.content.res.Resources;
import android.opengl.GLU;
import android.util.Log;

import com.google.android.stardroid.R;
import com.google.android.stardroid.renderer.LabelOverlayManager.Label;
import com.google.android.stardroid.renderer.util.ColoredQuad;
import com.google.android.stardroid.renderer.util.SearchHelper;
import com.google.android.stardroid.renderer.util.TextureManager;
import com.google.android.stardroid.units.GeocentricCoordinates;
import com.google.android.stardroid.units.Vector3;
import com.google.android.stardroid.util.MathUtil;
import com.google.android.stardroid.util.Matrix4x4;
import com.google.android.stardroid.util.VectorUtil;

import javax.microedition.khronos.opengles.GL10;

public class OverlayManager extends RendererObjectManager
{
	private int mWidth = 2;
	private int mHeight = 2;
	private Matrix4x4 mGeoToViewerTransform = Matrix4x4.createIdentity();
	private Vector3 mLookDir = new Vector3(0, 0, 0);
	private Vector3 mUpDir = new Vector3(0, 1, 0);
	private Vector3 mTransformedLookDir = new Vector3(0, 0, 0);
	private Vector3 mTransformedUpDir = new Vector3(0, 1, 0);
	private boolean mMustUpdateTransformedOrientation = true;

	private boolean mSearching = false;
	private boolean mImaging = false;
	private SearchHelper mSearchHelper = new SearchHelper();
	private SearchHelper mImageHelper = new SearchHelper();
	private ColoredQuad mDarkQuad = null;
	private SearchArrow mSearchArrow = new SearchArrow();
	private CrosshairOverlay mCrosshair = new CrosshairOverlay();
	private ImageOverlay imageCrosshairOverlay = new ImageOverlay();

	private TextureManager mTextureManager;

	public OverlayManager(int layer, TextureManager manager) {
		super(layer, manager);
	}

	@Override
	public void reload(GL10 gl, boolean fullReload)
	{
		Resources res = getRenderState().getResources();
		mSearchArrow.reloadTextures(gl, res, textureManager());
		mCrosshair.reloadTextures(gl, res, textureManager());
		imageCrosshairOverlay.reloadTextures(gl, res, textureManager());
	}

	public void resize(GL10 gl, int screenWidth, int screenHeight)
	{
		mWidth = screenWidth;
		mHeight = screenHeight;

		// If the search target is within this radius of the center of the
		// screen, the user is
		// considered to have "found" it.
		float searchTargetRadius = Math.min(screenWidth, screenHeight) - 20;
		mSearchHelper.setTargetFocusRadius(searchTargetRadius);
		mSearchHelper.resize(screenWidth, screenHeight);
		
		mImageHelper.setTargetFocusRadius(searchTargetRadius);
		mImageHelper.resize(screenWidth, screenHeight);
		
		mSearchArrow.resize(gl, screenWidth, screenHeight, searchTargetRadius);
		mCrosshair.resize(gl, screenWidth, screenHeight);
		imageCrosshairOverlay.resize(gl, screenWidth, screenHeight);

		mDarkQuad = new ColoredQuad(0, 0, 0, 0.6f, 0, 0, 0, screenWidth, 0, 0, 0, screenHeight, 0);
	}

	public void setViewOrientation(GeocentricCoordinates lookDir, GeocentricCoordinates upDir)
	{
		mLookDir = lookDir;
		mUpDir = upDir;
		mMustUpdateTransformedOrientation = true;
	}

	@Override
	public void drawInternal(GL10 gl)
	{
		updateTransformedOrientationIfNecessary();

		setupMatrices(gl);

		if (mSearching)
		{
			mSearchHelper.setTransform(getRenderState().getTransformToDeviceMatrix());
			mSearchHelper.checkState();

			float transitionFactor = mSearchHelper.getTransitionFactor();

			// Darken the background.
			mDarkQuad.draw(gl);

			// Draw the crosshair.
			mCrosshair.draw(gl, mSearchHelper, getRenderState().getNightVisionMode());

			// Draw the search arrow.
			mSearchArrow.draw(gl, mTransformedLookDir, mTransformedUpDir, mSearchHelper, getRenderState().getNightVisionMode());
		}
		
		if(mImaging)
		{
			//Log.e("on","on reload image");
			mImageHelper.setTransform(getRenderState().getTransformToDeviceMatrix());
			mImageHelper.checkState();
			imageCrosshairOverlay.draw(gl, mImageHelper, getRenderState().getNightVisionMode());
		}

		restoreMatrices(gl);
	}

	// viewerUp MUST be normalized.
	public void setViewerUpDirection(GeocentricCoordinates viewerUp)
	{
		// Log.d("OverlayManager", "Setting viewer up " + viewerUp);
		if (MathUtil.abs(viewerUp.y) < 0.999f)
		{
			Vector3 cp = VectorUtil.crossProduct(viewerUp, new Vector3(0, 1, 0));
			cp = VectorUtil.normalized(cp);
			mGeoToViewerTransform = Matrix4x4.createRotation(MathUtil.acos(viewerUp.y), cp);
		} else
		{
			mGeoToViewerTransform = Matrix4x4.createIdentity();
		}
		mMustUpdateTransformedOrientation = true;
	}

	public void enableSearchOverlay(GeocentricCoordinates target, String targetName)
	{
		Log.d("|OverlayManager|", "Searching for " + target + " name: " + targetName);
		mSearching = true;
		mSearchHelper.setTransform(getRenderState().getTransformToDeviceMatrix());
		mSearchHelper.setTarget(target, targetName);
		Vector3 transformedPosition = Matrix4x4.multiplyMV(mGeoToViewerTransform, target);
		mSearchArrow.setTarget(transformedPosition);
		queueForReload(false);
	}

	public void disableSearchOverlay()
	{
		mSearching = false;
	}
	
	
	public void enableImageOverlay(GeocentricCoordinates target, String targetName)
	{
		Log.e("Enable", "Queue to enable image");
		mImaging = true;
		mImageHelper.setTransform(getRenderState().getTransformToDeviceMatrix());
		mImageHelper.setTarget(target, targetName);
		//Vector3 transformedPosition = Matrix4x4.multiplyMV(mGeoToViewerTransform, target);
		//mSearchArrow.setTarget(transformedPosition);
		queueForReload(false);
	}
	
	public void disableImageOverlay()
	{
		mImaging = false;
	}

	private void setupMatrices(GL10 gl)
	{
		// Save the matrix values.
		gl.glMatrixMode(GL10.GL_PROJECTION);
		gl.glPushMatrix();
		gl.glLoadIdentity();

		gl.glMatrixMode(GL10.GL_MODELVIEW);
		gl.glPushMatrix();
		float left = mWidth / 2;
		float bottom = mHeight / 2;
		gl.glLoadIdentity();
		GLU.gluOrtho2D(gl, left, -left, bottom, -bottom);
	}

	private void restoreMatrices(GL10 gl)
	{
		// Restore the matrices.
		gl.glMatrixMode(GL10.GL_PROJECTION);
		gl.glPopMatrix();

		gl.glMatrixMode(GL10.GL_MODELVIEW);
		gl.glPopMatrix();
	}

	private void updateTransformedOrientationIfNecessary()
	{
		if (mMustUpdateTransformedOrientation && mSearching)
		{
			mTransformedLookDir = Matrix4x4.multiplyMV(mGeoToViewerTransform, mLookDir);
			mTransformedUpDir = Matrix4x4.multiplyMV(mGeoToViewerTransform, mUpDir);
			mMustUpdateTransformedOrientation = false;
		}
	}
}
